import akshare as ak
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime, timedelta


def fetch_etf_data(symbol, start_date, end_date):
    """
    Fetch ETF historical data from akshare
    """
    try:
        # For ETF funds, we use the fund_etf_hist_em interface
        df = ak.fund_etf_hist_em(symbol=symbol, period="daily",
                                 start_date=start_date, end_date=end_date)
        # Rename columns to standard names
        df.columns = [col.lower() for col in df.columns]
        if 'date' not in df.columns and '日期' in df.columns:
            df = df.rename(columns={'日期': 'date', '开盘': 'open', '收盘': 'close',
                                    '最高': 'high', '最低': 'low', '成交量': 'volume',
                                    '成交额': 'amount', '振幅': 'amplitude',
                                    '涨跌幅': 'change_pct', '涨跌额': 'change_amount'})

        # Convert date to datetime
        df['date'] = pd.to_datetime(df['date'])
        # Sort by date ascending
        df = df.sort_values('date')

        return df
    except Exception as e:
        print(f"Error fetching data: {e}")
        return None


def calculate_bias(df, periods=[34, 50, 70]):
    """
    Calculate BIAS for multiple periods
    BIAS = (Close - MA) / MA * 100%
    """
    for period in periods:
        col_name = f'ma_{period}'
        bias_name = f'bias_{period}'
        df[col_name] = df['close'].rolling(window=period).mean()
        df[bias_name] = (df['close'] - df[col_name]) / df[col_name] * 100
    return df


def calculate_williams_r(df, periods=[34, 50, 70]):
    """
    Calculate Williams %R for multiple periods
    WR = (Highest High - Close) / (Highest High - Lowest Low) * -100
    """
    for period in periods:
        highest_high = df['high'].rolling(window=period).max()
        lowest_low = df['low'].rolling(window=period).min()
        df[f'wr_{period}'] = (highest_high - df['close']) / (highest_high - lowest_low) * (-100)
    return df


def calculate_z_score(df, window=10, ema_period=3):
    """
    Calculate Z-Score momentum indicator
    Z-Score = (Close - Lowest Low) / (Highest High - Lowest Low) * 100
    Smoothed with EMA
    """
    highest_high = df['high'].rolling(window=window).max()
    lowest_low = df['low'].rolling(window=window).min()
    df['z_score'] = (df['close'] - lowest_low) / (highest_high - lowest_low) * 100
    # Apply EMA smoothing
    df['z_score_smoothed'] = df['z_score'].ewm(span=ema_period).mean()
    return df


def calculate_volume_divergence(df):
    """
    Calculate volume divergence metrics
    - Volume comparison to previous lows
    - 5-day average turnover rate
    """
    # Calculate price changes
    df['price_change'] = df['close'].diff()

    # Mark local lows (where price change switches from negative to positive)
    df['is_local_low'] = (df['price_change'].shift(1) < 0) & (df['price_change'] > 0)

    # Calculate 5-day average turnover (using volume as proxy since turnover rate not directly available)
    df['vol_5d_avg'] = df['volume'].rolling(window=5).mean()

    # Calculate relative volume (current volume compared to the volume at previous low)
    df['relative_volume'] = np.nan

    # Find previous low points and compare volumes
    low_points = df[df['is_local_low']].index.tolist()
    for i in range(1, len(low_points)):
        current_idx = low_points[i]
        prev_idx = low_points[i - 1]

        if current_idx > 0 and prev_idx > 0:
            relative_vol = df.loc[current_idx, 'volume'] / df.loc[prev_idx, 'volume'] * 100
            df.loc[current_idx, 'relative_volume'] = relative_vol

    # For analysis we'll consider volume divergence when price makes new low but volume is 30% lower
    df['vol_price_divergence'] = ((df['close'] < df['close'].shift(1)) & 
                                  (df['volume'] < df['volume'].shift(1) * 0.7))

    return df

def main():
    # List of ETF symbols to analyze
    etf_symbols = [
        "512170",  # 医疗ETF
        # "512880",  # 电力ETF
        # "561560",  # 科创50ETF
        # "588000",  # 军工ETF
        # "512660",  # 新能源车ETF
        # "159766",  # 光伏ETF
        # "515790",  # 芯片ETF
        # "159855",  # 影视ETF
        # "159865",  # 养殖ETF
        # "159845",  # 中证1000ETF
        # "159742",  # 恒生科技指数ETF
        # "159707",  # 地产ETF
        # "515000",  # 科技ETF
        # "159949",  # 创业板50ETF
        # "159915",  # 创业板50ETF
        # "159937",  # 黄金ETF基金
        # "515210",  # 钢铁ETF
        # "515050",  # 5G通信ETF
        # "159928",  # 消费ETF
        # "513050",  # 中概互联网ETF
    ]
    
    # # Dictionary to store signals for all ETFs
    # all_signals = {}
    
    # Define the time period
    end_date = datetime.now().strftime("%Y%m%d")
    start_date = (datetime.now() - timedelta(days=360)).strftime("%Y%m%d")  # Last 12 months
    
    print(f"Analyzing {len(etf_symbols)} ETFs from {start_date} to {end_date}")
    
    for symbol in etf_symbols:
        try:
            print(f"\n{'='*50}")
            print(f"Processing ETF: {symbol}")
            
            # Fetch data
            df = fetch_etf_data(symbol, start_date, end_date)
            
            if df is None or df.empty:
                print(f"Failed to fetch data or empty dataset returned for {symbol}, skipping...")
                continue
            
            print(f"Successfully fetched {len(df)} records for {symbol}")
            
            # Calculate all indicators
            df = calculate_bias(df)
            df = calculate_williams_r(df)
            df = calculate_z_score(df)
            df = calculate_volume_divergence(df)
            
            # Print DataFrame as text
            print(f"\nDataFrame for ETF {symbol}:")
            print(df.to_string())
            
        except Exception as e:
            print(f"Error processing {symbol}: {e}")
            continue


if __name__ == "__main__":
    main()
